//
//  NSObject+MFAPMSwizzle.m
//  MFAPMManager
//
//  Created by zhang liyu on 2019/5/22.
//

#import "NSObject+MFAPMSwizzle.h"

#import <objc/runtime.h>

@implementation NSObject (MFAPMSwizzle)

+ (void)mfapm_swizzleClassSEL:(SEL)originSEL toSEL:(SEL)swizzleSEL{
    
    Class class = object_getClass(self);
    
    Method originMethod = class_getClassMethod(class, originSEL);
    Method swizzleMethod = class_getClassMethod(class, swizzleSEL);
    
    [self swizzleMethodWithOriginSEL:originSEL
                        originMethod:originMethod
                          swizzleSEL:swizzleSEL
                       swizzleMethod:swizzleMethod
                               class:class];
}

+ (void)mfapm_swizzleInstanceSEL:(SEL)originSEL toSEL:(SEL)swizzleSEL{

    Method originMethod = class_getInstanceMethod(self, originSEL);
    Method swizzleMethod = class_getInstanceMethod(self, swizzleSEL);
    
    [self swizzleMethodWithOriginSEL:originSEL
                        originMethod:originMethod
                          swizzleSEL:swizzleSEL
                       swizzleMethod:swizzleMethod
                               class:self];
}

+ (BOOL)mfapm_swizzleSEL:(SEL)sel fromClass:(Class)originalCls toClass:(Class)stubCls{
    
    Method originalMethod = class_getInstanceMethod(originalCls, sel);
    Method stubMethod = class_getInstanceMethod(stubCls, sel);
    
    if (!originalMethod || !stubMethod) {
        return NO;
    }
    
    method_exchangeImplementations(originalMethod, stubMethod);
    return YES;
}

#pragma mark - Swizzle Actions

+ (void)swizzleMethodWithOriginSEL:(SEL)originSEL
                      originMethod:(Method)originMethod
                        swizzleSEL:(SEL)swizzleSEL
                     swizzleMethod:(Method)swizzleMethod
                             class:(Class)cls {
    
    BOOL isAddMethod = class_addMethod(cls, originSEL, method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod));
    
    if(isAddMethod){
        class_replaceMethod(cls, swizzleSEL, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
    }else{
        method_exchangeImplementations(originMethod, swizzleMethod);
    }
}

@end
